<!DOCTYPE html>
<html>
<head><meta name="generator" content="Hexo 3.8.0">
  <meta charset="utf-8">
  

  
  <title>SmileYi</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta property="og:type" content="website">
<meta property="og:title" content="SmileYi">
<meta property="og:url" content="http://smileyi.gitee.io/index.html">
<meta property="og:site_name" content="SmileYi">
<meta property="og:locale" content="zh-CN">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="SmileYi">
  
    <link rel="alternate" href="/atom.xml" title="SmileYi" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  
    <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  
  <link rel="stylesheet" href="/css/style.css">
</head>
</html>
<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">SmileYi</a>
      </h1>
      
        <h2 id="subtitle-wrap">
          <a href="/" id="subtitle">只要学会破罐子破摔 世界就会豁然开朗</a>
        </h2>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">首页</a>
        
          <a class="main-nav-link" href="/archives">归档</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="搜索"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://smileyi.gitee.io"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main">
  
    <article id="post-Swoole之server" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2020/01/05/Swoole之server/" class="article-date">
  <time datetime="2020-01-05T02:45:12.000Z" itemprop="datePublished">2020-01-05</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/Swoole/">Swoole</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2020/01/05/Swoole之server/">swoole之server</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h3 id="serv-new-Swoole-Server-host-port-mode-sockType"><a href="#serv-new-Swoole-Server-host-port-mode-sockType" class="headerlink" title="$serv = new \Swoole\Server($host, $port, $mode, $sockType)"></a>$serv = new \Swoole\Server($host, $port, $mode, $sockType)</h3><h3 id="Server模式-mode"><a href="#Server模式-mode" class="headerlink" title="Server模式($mode)"></a>Server模式($mode)</h3><h4 id="1-SWOOLE-BASE模式"><a href="#1-SWOOLE-BASE模式" class="headerlink" title="1.SWOOLE_BASE模式"></a>1.SWOOLE_BASE模式</h4><p><img src="/image/200105/01.jpg" alt="01"><br>基础模式模式，woker进程即监听socket事件，又执行业务处理，并发数相对于reactor模式来说较弱。当（serv-&gt;worker_num == 1 &amp;&amp; serv-&gt;task_worker_num == 0 &amp;&amp; serv-&gt;max_request == 0 &amp;&amp; serv-&gt;user_worker_list == NULL;）时，底层不在fork worker与task进程，manager进程即worker进程。</p>
<h4 id="2-SWOOLE-PROCESS模式"><a href="#2-SWOOLE-PROCESS模式" class="headerlink" title="2.SWOOLE_PROCESS模式"></a>2.SWOOLE_PROCESS模式</h4><p><img src="/image/200105/02.png" alt="01"></p>
<ul>
<li>master进程：1.创建manager进程、reactor线程、心跳检测进程；2.给worker进程分配任务</li>
<li>manager进程：创建管理worker进程与task进程</li>
<li>worker进程：处理业务逻辑</li>
<li>task进程：处理worker进程投递的任务</li>
<li>reactor线程：监听各个socket上的事件发生</li>
</ul>
<h3 id="socketType套接字类型"><a href="#socketType套接字类型" class="headerlink" title="socketType套接字类型"></a>socketType套接字类型</h3><table>
<thead>
<tr>
<th></th>
<th>同主机</th>
<th>跨主机</th>
</tr>
</thead>
<tbody>
<tr>
<td>流式数据</td>
<td>SWOOLE_UNIX_STREAM</td>
<td>SWOOLE_SOCK_TCP(6)</td>
</tr>
<tr>
<td>包式数据</td>
<td>SWOOLE_UNIX_DGRAM</td>
<td>SWOOLE_SOCK_UDP(6)</td>
</tr>
</tbody>
</table>
<p>流式数据在传递数据之前需要先建立连接，拥有额外的回调事件（onConnect、onClose），接受数据的回调事件为onReceive；包式数据不需要建立连接，接受数据的回调时间为onPacket。</p>
<p>同主机间通过unix_socket进行收发数据，不许要经过网络协议站，速度快于ip通信</p>
<h3 id="server相关配置"><a href="#server相关配置" class="headerlink" title="server相关配置"></a>server相关配置</h3><p>reactor_num(reactor线程数)、worker_num(工作进程数)、max_request(worker最大处理请求数)、max_conn(serv维持的最大连接数)、task_worker_num(任务进程数)、task_ipc_mode(task与worker的通信方式)、task_max_request(task进程最大处理任务数)，比较易于理解.</p>
<h4 id="1-dispatch-mode-master进程给worker进程分配任务的模式"><a href="#1-dispatch-mode-master进程给worker进程分配任务的模式" class="headerlink" title="1.dispatch_mode(master进程给worker进程分配任务的模式)"></a>1.dispatch_mode(master进程给worker进程分配任务的模式)</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">enum swFactory_dispatch_mode</span><br><span class="line">&#123;</span><br><span class="line">    SW_DISPATCH_ROUND    = 1,   //轮训模式</span><br><span class="line">    SW_DISPATCH_FDMOD    = 2,   //固定模式（默认）根据连接的文件描述符分配</span><br><span class="line">    SW_DISPATCH_QUEUE    = 3,   //根据Worker的忙闲状态选择投递</span><br><span class="line">    SW_DISPATCH_IPMOD    = 4,   //IP地址取模投递</span><br><span class="line">    SW_DISPATCH_UIDMOD   = 5,   //根据业务参数（UID）取模分配，UID需要自行设置</span><br><span class="line">    SW_DISPATCH_USERFUNC = 6,   //自定义分配方式，无需设置，当配置dispatch_func时，底层自动奇幻</span><br><span class="line">    SW_DISPATCH_STREAM   = 7,   //空闲的Worker会accept连接，并接受Reactor的新请求</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>注意，当配置伪1、3、7时，底层不支持非安全事件（onConnect onClose onBufferFull onBufferEmpty）</p>
<h4 id="2-tcp-defer-accept-延迟触发accept"><a href="#2-tcp-defer-accept-延迟触发accept" class="headerlink" title="2.tcp_defer_accept(延迟触发accept)"></a>2.tcp_defer_accept(延迟触发accept)</h4><p>当设置tcp_defer_accept =&gt; 5时，客户端与服务器建立连接时并不会立刻出发onConnect事件，直到接受到客户端发来的数据获超过5s</p>
<h4 id="3-backlog"><a href="#3-backlog" class="headerlink" title="3.backlog"></a>3.backlog</h4><p>代表服务端可容纳多少个待accept的连接。（与内核参数net.core.somaxconn取最小；半连接容纳数由内核参数net.ipv4.tcp_max_syn_backlog控制）</p>
<h4 id="4-heartbeat-check-interval和heartbeat-idle-time"><a href="#4-heartbeat-check-interval和heartbeat-idle-time" class="headerlink" title="4.heartbeat_check_interval和heartbeat_idle_time"></a>4.heartbeat_check_interval和heartbeat_idle_time</h4><p>心跳检测线程相关参数。心跳检测线程每隔heartbeat_check_interval时间对connect_list内的连接进行遍历，当发现有链接在heartbeat_idle_time时间内未发送任何数据，就会断开此连接</p>
<h4 id="5-open-cpu-affinity"><a href="#5-open-cpu-affinity" class="headerlink" title="5.open_cpu_affinity"></a>5.open_cpu_affinity</h4><p>CPU亲和设置，可以线程绑定到一个固定的cpu核心上面，减少上下文切换次数，提高cpu缓存的命中率。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"># static int swReactorThread_loop(swThreadParam *param)</span><br><span class="line">#ifdef HAVE_CPU_AFFINITY</span><br><span class="line">    //cpu affinity setting</span><br><span class="line">    if (serv-&gt;open_cpu_affinity)</span><br><span class="line">    &#123;</span><br><span class="line">        cpu_set_t cpu_set;</span><br><span class="line">        CPU_ZERO(&amp;cpu_set);</span><br><span class="line"> </span><br><span class="line">        if (serv-&gt;cpu_affinity_available_num)</span><br><span class="line">        &#123;</span><br><span class="line">            CPU_SET(serv-&gt;cpu_affinity_available[reactor_id % serv-&gt;cpu_affinity_available_num], &amp;cpu_set);</span><br><span class="line">        &#125;</span><br><span class="line">        else</span><br><span class="line">        &#123;</span><br><span class="line">            CPU_SET(reactor_id % SW_CPU_NUM, &amp;cpu_set);</span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        if (0 != pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &amp;cpu_set))</span><br><span class="line">        &#123;</span><br><span class="line">            swSysWarn(&quot;pthread_setaffinity_np() failed&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">#endif</span><br></pre></td></tr></table></figure>
<h4 id="6-tcp-fastopen"><a href="#6-tcp-fastopen" class="headerlink" title="6.tcp_fastopen"></a>6.tcp_fastopen</h4><p>tcp快速握手特性，需要linux内核大于3.6。第一次和客户端正常连接之生成一个cookie给客户端，之后客户端根据这个cookie可直接与服务端建立连接<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">swPort_listen(swListenPort *ls) &#123;</span><br><span class="line">...</span><br><span class="line">listen(sock, ls-&gt;backlog)</span><br><span class="line">...</span><br><span class="line">#ifdef TCP_FASTOPEN</span><br><span class="line">    if (ls-&gt;tcp_fastopen)</span><br><span class="line">    &#123;</span><br><span class="line">        if (setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, (const void*) &amp;ls-&gt;tcp_fastopen, sizeof(int)) != 0)</span><br><span class="line">        &#123;</span><br><span class="line">            swSysWarn(&quot;setsockopt(TCP_FASTOPEN) failed&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">#endif</span><br><span class="line">...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h4 id="7-max-wait-time"><a href="#7-max-wait-time" class="headerlink" title="7.max_wait_time"></a>7.max_wait_time</h4><p>woker进程需要停止时（到达max_request或者接受到SIGTERM信号），最大的等待时间，超过这个时间还未停止，则强制终止。</p>
<h4 id="8-enable-delay-receive"><a href="#8-enable-delay-receive" class="headerlink" title="8.enable_delay_receive"></a>8.enable_delay_receive</h4><p>开启后、accept连线不会自动加入reactor事件循环，由业务层手动加入</p>
<h3 id="回调事件"><a href="#回调事件" class="headerlink" title="回调事件"></a>回调事件</h3><table>
<thead>
<tr>
<th>回调函数</th>
<th>参数</th>
<th>时机</th>
<th>所在进程/线程</th>
</tr>
</thead>
<tbody>
<tr>
<td>start</td>
<td>$serv</td>
<td>master进程启动</td>
<td>master</td>
</tr>
<tr>
<td>managerStart</td>
<td>$serv</td>
<td>manager进程启动</td>
<td>manager</td>
</tr>
<tr>
<td>workerStart</td>
<td>$serv, $worderId</td>
<td>worker/task进程启动</td>
<td>worker/task</td>
</tr>
<tr>
<td>connect</td>
<td>$serv, $fd, $reactorId</td>
<td>tcp建立连接</td>
<td>master</td>
</tr>
<tr>
<td>receive</td>
<td>$serv, $fd, $reactorId, $data</td>
<td>reactor</td>
</tr>
<tr>
<td>close</td>
<td>$serv, $fd, $reactorId</td>
<td>tcp连接断开</td>
<td>reactor</td>
</tr>
<tr>
<td>packet</td>
<td>$serv, $data, $clientInfo</td>
<td>接受到UDP数据</td>
<td>?</td>
</tr>
<tr>
<td>workerStop</td>
<td>$serv, $workerId</td>
<td>worker/task进程结束</td>
<td>worker</td>
</tr>
<tr>
<td>managerStop</td>
<td>$serv</td>
<td>manager进程结束</td>
<td>managerStop</td>
</tr>
<tr>
<td>shutdown</td>
<td>$serv</td>
<td>主进程结束</td>
<td>manager</td>
</tr>
<tr>
<td>task</td>
<td>$serv, $taskId, $workerId, $data</td>
<td>worker进程中投递任务</td>
<td>worker</td>
</tr>
<tr>
<td>finish</td>
<td>$serv, $taskId, $data</td>
<td>task进程完成任务时</td>
<td>task</td>
</tr>
</tbody>
</table>
<h3 id="基础数据结构"><a href="#基础数据结构" class="headerlink" title="基础数据结构"></a>基础数据结构</h3><h4 id="server"><a href="#server" class="headerlink" title="server"></a>server</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br></pre></td><td class="code"><pre><span class="line">struct _swServer</span><br><span class="line">&#123;</span><br><span class="line">    uint16_t reactor_num;   //reactor线程数亮，高于worker_num</span><br><span class="line">    uint32_t worker_num;    //工作进程数</span><br><span class="line">    uint16_t reactor_pipe_num;  //用来计算通信管道；等于worker_num / reactor_num;</span><br><span class="line">    uint8_t factory_mode;   //多进程模型还是reactor模型</span><br><span class="line">    uint8_t dispatch_mode;  //worker进程的分配模式 可通过set直接设置</span><br><span class="line">    int worker_uid;</span><br><span class="line">    int worker_groupid;</span><br><span class="line">    uint32_t max_connection;  //最大连接数</span><br><span class="line">    uint32_t max_request;   //单个worker进程的最大请求数 可通过set直接设置</span><br><span class="line">    uint32_t max_request_grace;</span><br><span class="line">    uint32_t max_wait_time; //工作进程结束时最大的等待时间，可通过set直接设置</span><br><span class="line"> </span><br><span class="line">    //reactor线程调度相关参数</span><br><span class="line">    uint16_t reactor_round_i;</span><br><span class="line">    uint16_t reactor_next_i;</span><br><span class="line">    uint16_t reactor_schedule_count;</span><br><span class="line"> </span><br><span class="line">    uint32_t daemonize :1;  //是否以守护进程方式启动，可通过set直接设置</span><br><span class="line">    uint32_t have_dgram_sock :1;  //监听列表是否包含包式IO流 UDP(6) UNIX_SOCKET_DGRAM</span><br><span class="line">    uint32_t have_stream_sock :1; //同have_dgram_sock 判断流式IO</span><br><span class="line">    uint32_t open_cpu_affinity :1; //是否开启cpu亲和设置 可通过set直接设置</span><br><span class="line">    uint32_t discard_timeout_request :1;  //对于已经断开的连接，worker是否还需要处理 可通过set设置</span><br><span class="line">     </span><br><span class="line">    //Http相关参数 是否开启zip压缩，是否处理景泰文件</span><br><span class="line">    ....</span><br><span class="line">     </span><br><span class="line">    uint32_t enable_unsafe_event :1; //是否支持非安全回调事件 （connect、close、bufferFull、bufferEmpty）</span><br><span class="line">    uint32_t enable_delay_receive :1; //accept连线后是否加入自动加入事件循环 set直接设置</span><br><span class="line">    uint32_t task_use_object :1;  //task回调函数是否使用对象 set直接设置</span><br><span class="line"> </span><br><span class="line">    //心跳检测参数</span><br><span class="line">    uint16_t heartbeat_idle_time;</span><br><span class="line">    uint16_t heartbeat_check_interval;</span><br><span class="line">     </span><br><span class="line">    //cpu亲和相关设置</span><br><span class="line">    int *cpu_affinity_available;</span><br><span class="line">    int cpu_affinity_available_num;</span><br><span class="line"> </span><br><span class="line">    swFactory factory;  //工厂对象 **************</span><br><span class="line">    swListenPort *listen_list;  //监听的socket列表</span><br><span class="line">    pthread_t heartbeat_pidt;   //心跳检测线程</span><br><span class="line"> </span><br><span class="line">    //任务进程相关</span><br><span class="line">    uint32_t task_worker_num;</span><br><span class="line">    uint8_t task_ipc_mode;</span><br><span class="line">    uint32_t task_max_request;</span><br><span class="line">    uint32_t task_max_request_grace;</span><br><span class="line">    swPipe *task_notify;</span><br><span class="line">    swEventData *task_result;</span><br><span class="line"> </span><br><span class="line">    //用户自定义进程  通过Server-&gt;addProcess(Process $process);添加</span><br><span class="line">    uint32_t user_worker_num;</span><br><span class="line">    swUserWorker_node *user_worker_list;</span><br><span class="line">    swHashMap *user_worker_map;</span><br><span class="line">    swWorker *user_workers;</span><br><span class="line">     </span><br><span class="line">    swReactorThread *reactor_threads;  //reactor线程</span><br><span class="line">    swWorker *workers;   //worker线程</span><br><span class="line"> </span><br><span class="line">    swConnection *connection_list;   //同下</span><br><span class="line">    swSession *session_list;    //已建立的链接</span><br><span class="line"> </span><br><span class="line">    void (*onStart)(swServer *serv);</span><br><span class="line">    void (*onManagerStart)(swServer *serv);</span><br><span class="line">    void (*onManagerStop)(swServer *serv);</span><br><span class="line">    void (*onShutdown)(swServer *serv);</span><br><span class="line">    void (*onPipeMessage)(swServer *, swEventData *);</span><br><span class="line">    void (*onWorkerStart)(swServer *serv, int worker_id);</span><br><span class="line">    void (*onWorkerStop)(swServer *serv, int worker_id);</span><br><span class="line">    void (*onWorkerExit)(swServer *serv, int worker_id);</span><br><span class="line">    void (*onWorkerError)(swServer *serv, int worker_id, pid_t worker_pid, int exit_code, int signo);</span><br><span class="line">    void (*onUserWorkerStart)(swServer *serv, swWorker *worker);</span><br><span class="line">     </span><br><span class="line">    //worker进程方法</span><br><span class="line">    int (*onReceive)(swServer *, swEventData *);</span><br><span class="line">    int (*onPacket)(swServer *, swEventData *);</span><br><span class="line">    void (*onClose)(swServer *serv, swDataHead *);</span><br><span class="line">    void (*onConnect)(swServer *serv, swDataHead *);</span><br><span class="line">    void (*onBufferFull)(swServer *serv, swDataHead *);</span><br><span class="line">    void (*onBufferEmpty)(swServer *serv, swDataHead *);</span><br><span class="line">     </span><br><span class="line">    //task进程方法</span><br><span class="line">    int (*onTask)(swServer *serv, swEventData *data);</span><br><span class="line">    int (*onFinish)(swServer *serv, swEventData *data);</span><br><span class="line">     </span><br><span class="line">    //server方法</span><br><span class="line">    int (*send)(swServer *serv, int session_id, void *data, uint32_t length);</span><br><span class="line">    int (*sendfile)(swServer *serv, int session_id, const char *file, uint32_t l_file, off_t offset, size_t length);</span><br><span class="line">    int (*sendwait)(swServer *serv, int session_id, void *data, uint32_t length);</span><br><span class="line">    int (*close)(swServer *serv, int session_id, int reset);</span><br><span class="line">    int (*notify)(swServer *serv, swConnection *conn, int event);</span><br><span class="line">    int (*feedback)(swServer *serv, int session_id, int event);</span><br><span class="line">     </span><br><span class="line">    //worker分配自定义方式</span><br><span class="line">    int (*dispatch_func)(swServer *, swConnection *, swSendData *);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h4 id="worker进程"><a href="#worker进程" class="headerlink" title="worker进程"></a>worker进程</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">struct _swWorker</span><br><span class="line">&#123;</span><br><span class="line"> </span><br><span class="line">    pid_t pid;</span><br><span class="line">    pthread_t tid;</span><br><span class="line">    swProcessPool *pool;</span><br><span class="line">    swMemoryPool *pool_output;</span><br><span class="line">    swMsgQueue *queue;</span><br><span class="line"> </span><br><span class="line">    //输入输出</span><br><span class="line">    uint8_t redirect_stdout :1;</span><br><span class="line">    uint8_t redirect_stdin :1;</span><br><span class="line">    uint8_t redirect_stderr :1;</span><br><span class="line">    uint8_t status;  //进程状态 空闲 or busy</span><br><span class="line">    uint8_t type;</span><br><span class="line">    uint8_t ipc_mode;  //与master通信方式</span><br><span class="line">    uint8_t child_process;</span><br><span class="line"> </span><br><span class="line">    sw_atomic_t tasking_num;</span><br><span class="line"> </span><br><span class="line">    time_t start_time;</span><br><span class="line"> </span><br><span class="line">    long dispatch_count;  //被分派的次数</span><br><span class="line">    long request_count;   //处理的请求数/任务数  大于max_request执行swWorker_stop(worker);</span><br><span class="line">    uint32_t id;</span><br><span class="line"> </span><br><span class="line">    swLock lock;</span><br><span class="line"> </span><br><span class="line">    swPipe *pipe_object;</span><br><span class="line"> </span><br><span class="line">    int pipe_master;    //与主进程的通信fd</span><br><span class="line">    int pipe_worker;</span><br><span class="line"> </span><br><span class="line">    int pipe;</span><br><span class="line">    void *ptr;</span><br><span class="line">    void *ptr2;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h4 id="reactor线程"><a href="#reactor线程" class="headerlink" title="reactor线程"></a>reactor线程</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">struct _swReactor</span><br><span class="line">&#123;</span><br><span class="line">    void *ptr;  //一般指向server对象</span><br><span class="line"> </span><br><span class="line">    int singal_no;  //信号值 处理之后置为0</span><br><span class="line"> </span><br><span class="line">    uint32_t event_num;   //已监听的fd个数</span><br><span class="line">    uint32_t max_event_num; //监听fd最大个数</span><br><span class="line"> </span><br><span class="line">    uint16_t id;    //reactorID</span><br><span class="line">    uint16_t flag;  //监听事件的标志位  EPOLLIN|EPOLLOUT|EPOLLONESHOT|(EPOLLRDHUP | EPOLLHUP | EPOLLERR)</span><br><span class="line"> </span><br><span class="line">    uint32_t max_socket;  //最大连接数 等于server的max_connection</span><br><span class="line">    swArray *socket_array; //监听的socket列表</span><br><span class="line">     </span><br><span class="line">    //socket的管理函数</span><br><span class="line">    int (*add)(swReactor *, int fd, int fdtype);  //epoll_ctl</span><br><span class="line">    int (*set)(swReactor *, int fd, int fdtype);  //epoll_ctl</span><br><span class="line">    int (*del)(swReactor *, int fd);  //epoll_ctl</span><br><span class="line">    int (*wait)(swReactor *, struct timeval *);   //epoll_wait</span><br><span class="line">    void (*free)(swReactor *);</span><br><span class="line"> </span><br><span class="line">    void *defer_tasks;</span><br><span class="line">    void *destroy_callbacks;</span><br><span class="line"> </span><br><span class="line">    swDefer_callback idle_task;</span><br><span class="line">    swDefer_callback future_task;</span><br><span class="line"> </span><br><span class="line">    void (*onTimeout)(swReactor *);</span><br><span class="line">    void (*onFinish)(swReactor *);</span><br><span class="line">    void (*onBegin)(swReactor *);</span><br><span class="line"> </span><br><span class="line">    void (*enable_accept)(swReactor *);</span><br><span class="line">    int (*is_empty)(swReactor *);</span><br><span class="line"> </span><br><span class="line">    int (*write)(swReactor *, int, const void *, int);</span><br><span class="line">    int (*close)(swReactor *, int);</span><br><span class="line">    void (*defer)(swReactor *, swCallback, void *);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h4 id="serverFactory"><a href="#serverFactory" class="headerlink" title="serverFactory"></a>serverFactory</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line">src/server/process.cc</span><br><span class="line">swFactoryProcess_create（）</span><br><span class="line">struct _swFactory</span><br><span class="line">&#123;</span><br><span class="line">    void *object;</span><br><span class="line">    void *ptr; //指向serv</span><br><span class="line">     </span><br><span class="line">    //启动</span><br><span class="line">    int (*start)(struct _swFactory *) &#123;</span><br><span class="line">        swManager_start(serv) &#123;</span><br><span class="line">            //fork mananger进程</span><br><span class="line">            pid = swoole_fork(0);</span><br><span class="line">            if pid == 0 &#123;</span><br><span class="line">                //mananger进程中...</span><br><span class="line">                //fork task worker 触发onWorkStart事件 启动main-loop事件循环 结束后触发onWorkStop事件</span><br><span class="line">                swProcessPool_start(&amp;serv-&gt;gs-&gt;task_workers) &amp;&amp; swProcessPool_spawn(pool, &amp;(pool-&gt;workers[i]))</span><br><span class="line">                 </span><br><span class="line">                //fork worker进程 启动worker事件循环  触发swWorker_onStart(serv);事件</span><br><span class="line">                swManager_spawn_worker(serv, i) &amp;&amp; swWorker_loop(serv, worker_id) &#123;</span><br><span class="line">                    //触发onWorkStart事件</span><br><span class="line">                    swWorker_onStart(serv);</span><br><span class="line">                    //进入reactor事件循环</span><br><span class="line">                    reactor-&gt;wait(reactor, NULL);</span><br><span class="line">                     </span><br><span class="line">                    //结束后触发onWorkStop事件</span><br><span class="line">                    swWorker_onStop(serv);</span><br><span class="line">                &#125;</span><br><span class="line">                //fork用户自定义进程</span><br><span class="line">                swManager_spawn_user_worker(serv, user_worker-&gt;worker);</span><br><span class="line">            &#125;</span><br><span class="line">            if pid &gt; 0 &#123;</span><br><span class="line">                serv-&gt;gs-&gt;manager_pid = pid;   //写入manager_pid</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    int (*shutdown)(struct _swFactory *);</span><br><span class="line">     </span><br><span class="line">    //投递客户端数据</span><br><span class="line">    int (*dispatch)(struct _swFactory *, swSendData *) &#123;</span><br><span class="line">        //获取目标workerid</span><br><span class="line">        int target_worker_id = swServer_worker_schedule(serv, fd, task);</span><br><span class="line">        //获取worker</span><br><span class="line">        swWorker *worker = swServer_get_worker(serv, target_worker_id);</span><br><span class="line">        //将数据和任务投递给worker进程  (pipe_fd = worker-&gt;pipe_master &amp;&amp; write(pipe_fd, (void *) data, len))</span><br><span class="line">        swReactorThread_send2worker(swServer *serv, swWorker *worker, void *data, int len)</span><br><span class="line">    &#125;</span><br><span class="line">     </span><br><span class="line">    //向客户端发送数据</span><br><span class="line">    int (*finish)(struct _swFactory *, swSendData *) &#123;</span><br><span class="line">        //从server-&gt;session_list中拿到链接</span><br><span class="line">        conn = swServer_connection_verify(serv, session_id);</span><br><span class="line">        //将数据发送给reactor线程</span><br><span class="line">        swWorker_send2reactor() &#123;</span><br><span class="line">            获取与reactor通信的fd 然后写入</span><br><span class="line">            _pipe_fd = swServer_get_send_pipe(serv, session_id, ev_data-&gt;info.reactor_id)</span><br><span class="line">            &amp;&amp; SwooleTG.reactor-&gt;write(SwooleTG.reactor, _pipe_fd, ev_data, sendn);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    int (*notify)(struct _swFactory *, swDataHead *);    //send a event notify</span><br><span class="line">    int (*end)(struct _swFactory *, int fd);</span><br><span class="line">    void (*free)(struct _swFactory *);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="server启动伪代码"><a href="#server启动伪代码" class="headerlink" title="server启动伪代码"></a>server启动伪代码</h3><h4 id="1-加载swoole扩展时的回调"><a href="#1-加载swoole扩展时的回调" class="headerlink" title="1.加载swoole扩展时的回调"></a>1.加载swoole扩展时的回调</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">PHP_MINIT_FUNCTION(swoole)</span><br><span class="line">&#123;</span><br><span class="line">    //定义全局常量</span><br><span class="line">    SW_REGISTER_LONG_CONSTANT(&quot;SWOOLE_BASE&quot;, SW_MODE_BASE);</span><br><span class="line">    SW_REGISTER_LONG_CONSTANT(&quot;SWOOLE_PROCESS&quot;, SW_MODE_PROCESS);</span><br><span class="line"> </span><br><span class="line">    //初始化swoole</span><br><span class="line">    swoole_sinit() &#123;</span><br><span class="line">        //设置全局配置</span><br><span class="line">        SwooleG.running = 1;</span><br><span class="line">        SwooleG.init = 1;</span><br><span class="line">        SwooleG.enable_coroutine = 1</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">        //申请全局内存</span><br><span class="line">        SwooleG.memory_pool = swMemoryGlobal_new(SW_GLOBAL_MEMORY_PAGESIZE, 1);</span><br><span class="line">         </span><br><span class="line">        //初始化线程锁</span><br><span class="line">        pthread_mutex_init()</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    //初始化异常类</span><br><span class="line">    SW_INIT_CLASS_ENTRY_EX2</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="2-serv构造函数"><a href="#2-serv构造函数" class="headerlink" title="2.serv构造函数"></a>2.serv构造函数</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">static PHP_METHOD(swoole_server, __construct)&#123;</span><br><span class="line">    //一堆参数检测SWOOLE_G(cli)、SwooleTG.reactor、SwooleG.serv</span><br><span class="line">     </span><br><span class="line">    //创建serv对象并初始化</span><br><span class="line">    swServer *serv = (swServer *) sw_malloc(sizeof (swServer));</span><br><span class="line">    swServer_init(serv)</span><br><span class="line"> </span><br><span class="line">    //建立socket、绑定端口，并将端口对象追加到listen_list中</span><br><span class="line">    swListenPort *port = swServer_add_port(serv, (enum swSocket_type) sock_type, host, serv_port) &#123;</span><br><span class="line">        int sock = swSocket_create(ls-&gt;type);</span><br><span class="line">        swSocket_bind(sock, ls-&gt;type, ls-&gt;host, &amp;ls-&gt;port)</span><br><span class="line">        LL_APPEND(serv-&gt;listen_list, ls);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-serv-gt-start-函数"><a href="#3-serv-gt-start-函数" class="headerlink" title="3.serv-&gt;start()函数"></a>3.serv-&gt;start()函数</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br></pre></td><td class="code"><pre><span class="line">static PHP_METHOD(swoole_server, start) &#123;</span><br><span class="line">    //注册回调函数</span><br><span class="line">    php_swoole_server_register_callbacks(serv);</span><br><span class="line">     </span><br><span class="line">    //启动server</span><br><span class="line">    swServer_start(serv) &#123;</span><br><span class="line">        //serv属性的检测和调整</span><br><span class="line">        swServer_start_check(serv)</span><br><span class="line"> </span><br><span class="line">        //master进程</span><br><span class="line">        serv-&gt;gs-&gt;master_pid = getpid();</span><br><span class="line">        serv-&gt;gs-&gt;now = serv-&gt;stats-&gt;start_time = time(NULL);</span><br><span class="line">         </span><br><span class="line">        //初始化函数</span><br><span class="line">        serv-&gt;send = swServer_tcp_send;</span><br><span class="line">        serv-&gt;sendwait = swServer_tcp_sendwait;</span><br><span class="line">        serv-&gt;sendfile = swServer_tcp_sendfile;</span><br><span class="line">        serv-&gt;close = swServer_tcp_close;</span><br><span class="line">        serv-&gt;notify = swServer_tcp_notify;</span><br><span class="line">        serv-&gt;feedback = swServer_tcp_feedback;</span><br><span class="line"> </span><br><span class="line">        //创建worker进程对象</span><br><span class="line">        serv-&gt;workers = (swWorker *) SwooleG.memory_pool-&gt;alloc(SwooleG.memory_pool, serv-&gt;worker_num * sizeof(swWorker));</span><br><span class="line">        serv-&gt;gs-&gt;event_workers.workers = serv-&gt;workers;</span><br><span class="line"> </span><br><span class="line">        //创建task与worker进程的通信管道和响应结果 task_worker_num &gt;= 1</span><br><span class="line">        serv-&gt;task_result = (swEventData *) sw_shm_calloc(serv-&gt;worker_num, sizeof(swEventData));</span><br><span class="line">        serv-&gt;task_notify = (swPipe *) sw_calloc(serv-&gt;worker_num, sizeof(swPipe));</span><br><span class="line">        foreach  &#123; swPipeNotify_auto(&amp;serv-&gt;task_notify[i], 1, 0)&#125;</span><br><span class="line">       </span><br><span class="line">        //启动manager、worker、task</span><br><span class="line">        factory-&gt;start(factory) &#123;</span><br><span class="line">            swManager_start(serv) &#123;</span><br><span class="line">                //fork mananger进程</span><br><span class="line">                pid = swoole_fork(0);</span><br><span class="line">                if pid == 0 &#123;</span><br><span class="line">                    //mananger进程中...</span><br><span class="line"> </span><br><span class="line">                    //fork task worker 触发onWorkStart事件 启动main-loop事件循环 结束后触发onWorkStop事件</span><br><span class="line">                    swProcessPool_start(&amp;serv-&gt;gs-&gt;task_workers) &amp;&amp; swProcessPool_spawn(pool, &amp;(pool-&gt;workers[i]))</span><br><span class="line">                     </span><br><span class="line">                    //fork worker进程 启动worker事件循环  触发swWorker_onStart(serv);事件</span><br><span class="line">                    swManager_spawn_worker(serv, i) &amp;&amp; swWorker_loop(serv, worker_id) &#123;</span><br><span class="line">                        //触发onWorkStart事件</span><br><span class="line">                        swWorker_onStart(serv);</span><br><span class="line"> </span><br><span class="line">                        //进入reactor事件循环</span><br><span class="line">                        reactor-&gt;wait(reactor, NULL);</span><br><span class="line">                         </span><br><span class="line">                        //结束后触发onWorkStop事件</span><br><span class="line">                        swWorker_onStop(serv);</span><br><span class="line">                    &#125;</span><br><span class="line"> </span><br><span class="line">                    //fork用户自定义进程</span><br><span class="line">                    swManager_spawn_user_worker(serv, user_worker-&gt;worker);</span><br><span class="line">                &#125;</span><br><span class="line">                if pid &gt; 0 &#123;</span><br><span class="line">                    serv-&gt;gs-&gt;manager_pid = pid;   //写入manager_pid</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        //注册信号处理函数</span><br><span class="line">        swServer_signal_init(serv);</span><br><span class="line">         </span><br><span class="line">        //创建reactor进程、开启时间循环</span><br><span class="line">        ret = swReactorThread_start(serv) &#123;</span><br><span class="line">         </span><br><span class="line">            //监听端口列表</span><br><span class="line">            LL_FOREACH(serv-&gt;listen_list, ls) &#123;</span><br><span class="line">                swPort_listen(ls)</span><br><span class="line">                 </span><br><span class="line">                //将事件加入reactor列表   </span><br><span class="line">                reactor-&gt;add(reactor, ls-&gt;sock, SW_FD_STREAM_SERVER);</span><br><span class="line">            &#125;</span><br><span class="line">             </span><br><span class="line">            //启动reactor线程</span><br><span class="line">            for (i = 0; i &lt; serv-&gt;reactor_num; i++) &#123;</span><br><span class="line">                pthread_create(&amp;pidt, NULL, (void * (*)(void *)) swReactorThread_loop, (void *) param)</span><br><span class="line">            &#125;</span><br><span class="line">             </span><br><span class="line">            //开启心跳检测线程</span><br><span class="line">            if (serv-&gt;heartbeat_check_interval &gt;= 1 &amp;&amp; serv-&gt;heartbeat_check_interval &lt;= serv-&gt;heartbeat_idle_time)&#123;</span><br><span class="line">                swHeartbeatThread_start(serv);</span><br><span class="line">            &#125;</span><br><span class="line"> </span><br><span class="line">            //设置新链接到来的回调函数</span><br><span class="line">            swReactor_set_handler(reactor, SW_FD_STREAM_SERVER, swServer_master_onAccept); &#123;</span><br><span class="line">                //获取客户端连线</span><br><span class="line">                 new_fd = swSocket_accept(event-&gt;fd, &amp;event-&gt;socket-&gt;info);</span><br><span class="line">            &#125;</span><br><span class="line"> </span><br><span class="line">            //触发onStart回调函数</span><br><span class="line">            serv-&gt;onStart(serv);</span><br><span class="line"> </span><br><span class="line">            //开始事件等待</span><br><span class="line">            return swoole_event_wait();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="内核参数调整"><a href="#内核参数调整" class="headerlink" title="内核参数调整"></a>内核参数调整</h3><ul>
<li>net.unix.max_dgram_qlen = 100 //socket中可包含多少个数据报</li>
<li>net.ipv4.tcp_syncookies=1   //开启syncookie</li>
<li>net.ipv4.tcp_max_syn_backlog=81920  //socket最大接受的连接</li>
<li>net.ipv4.tcp_synack_retries=3   //第二次握手重试次数</li>
<li>net.ipv4.tcp_syn_retries=3  //第一次握手的重试次数</li>
<li>net.ipv4.tcp_fin_timeout = 30  //tcp FIN_WAIT_2状态的登台时间</li>
<li>net.ipv4.tcp_keepalive_time = 300  //keepalive有效时间</li>
<li>net.ipv4.tcp_tw_reuse = 1  //允许重新应用处于TIME-WAIT状态的socket用于新的TCP连接</li>
<li>net.ipv4.tcp_tw_recycle = 1 //快速回收time-wait装太小的socket</li>
<li>net.ipv4.ip_local_port_range = 20000 65000 //端口范围</li>
<li>net.ipv4.tcp_max_tw_buckets = 200000  //time-wait最大值，超过之后不会在timewait</li>
<li>net.ipv4.route.max_size = 5242880</li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://smileyi.gitee.io/2020/01/05/Swoole之server/" data-id="ck5390ns6001qkecz32bvp8vt" class="article-share-link">分享</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/原创/">原创</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-Certbot-免费的ssl证书" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2020/01/02/Certbot-免费的ssl证书/" class="article-date">
  <time datetime="2020-01-02T03:10:33.000Z" itemprop="datePublished">2020-01-02</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/Nginx/">Nginx</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2020/01/02/Certbot-免费的ssl证书/">Certbot--免费的ssl证书</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h3 id="项目地址"><a href="#项目地址" class="headerlink" title="项目地址"></a>项目地址</h3><p><a href="https://github.com/certbot/certbot" target="_blank" rel="noopener">https://github.com/certbot/certbot</a></p>
<h3 id="配置证书"><a href="#配置证书" class="headerlink" title="配置证书"></a>配置证书</h3><h4 id="1-关闭站点（关闭域名解析获Nginx）"><a href="#1-关闭站点（关闭域名解析获Nginx）" class="headerlink" title="1.关闭站点（关闭域名解析获Nginx）"></a>1.关闭站点（关闭域名解析获Nginx）</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo nginx -s stop</span><br></pre></td></tr></table></figure>
<h4 id="2-生成证书"><a href="#2-生成证书" class="headerlink" title="2.生成证书"></a>2.生成证书</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">certbot certonly --email wangzy_smile@qq.com --standalone -d www.smileyi.cn -d blog.smileyi.cn -d resource.smileyi.cn</span><br></pre></td></tr></table></figure>
<p>证书有效期为三个月，记得三个月之内续期</p>
<h4 id="3-Nginx配置"><a href="#3-Nginx配置" class="headerlink" title="3.Nginx配置"></a>3.Nginx配置</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">    listen       80;</span><br><span class="line">    listen  443 ssl;</span><br><span class="line"></span><br><span class="line">    server_name  www.smileyi.cn smileyi.cn;</span><br><span class="line">    </span><br><span class="line">    ssl_certificate      /etc/letsencrypt/live/www.smileyi.cn/fullchain.pem;</span><br><span class="line">    ssl_certificate_key  /etc/letsencrypt/live/www.smileyi.cn/privkey.pem;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="4-启动Nginx"><a href="#4-启动Nginx" class="headerlink" title="4.启动Nginx"></a>4.启动Nginx</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo nginx</span><br></pre></td></tr></table></figure>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://smileyi.gitee.io/2020/01/02/Certbot-免费的ssl证书/" data-id="ck5390nqv0002keczbfp4yd04" class="article-share-link">分享</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/原创/">原创</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-Nginx限流配置" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2019/07/13/Nginx限流配置/" class="article-date">
  <time datetime="2019-07-13T07:23:19.000Z" itemprop="datePublished">2019-07-13</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/Nginx/">Nginx</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2019/07/13/Nginx限流配置/">Nginx限流配置</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h3 id="ngx-http-limit-conn-module模块"><a href="#ngx-http-limit-conn-module模块" class="headerlink" title="ngx_http_limit_conn_module模块"></a>ngx_http_limit_conn_module模块</h3><p>limit_conn_zone和limit_conn两个指令搭配，可以设定某个维度（客户端IP、域名）下同一时刻的最大连接数。例：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">http &#123;</span><br><span class="line">    //...</span><br><span class="line">    limit_conn_zone $binary_remote_addr zone=perip:10m;</span><br><span class="line"></span><br><span class="line">    server &#123;</span><br><span class="line">        //...</span><br><span class="line">        limit_conn perip 2; //该指令也可配置在location中</span><br><span class="line">        limit_rate 100k;    //每个链接限速为100k</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>上述配置表明同一IP在同一时刻的最大连接数为2。</p>
<h3 id="ngx-http-limit-req-module模块"><a href="#ngx-http-limit-req-module模块" class="headerlink" title="ngx_http_limit_req_module模块"></a>ngx_http_limit_req_module模块</h3><p>limit_req_zone和limit_req两个指令搭配，可以设定某个维度（客户端IP、域名）下的访问速率。例：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">http &#123;</span><br><span class="line">    //...</span><br><span class="line">    limit_req_zone $host zone=perhost:10m rate=5r/s;</span><br><span class="line"></span><br><span class="line">    server &#123;</span><br><span class="line">        //...</span><br><span class="line">        limit_req zone=perhost bursh=10 nodelay;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>该方式采用令牌桶算法，bursh=10代表桶内最大可存储10块令牌，rate=5r/s表示每秒向桶中加入5块令牌。上述配置表明同一个域名下1s内的最大连接速率为5（5qps），因为存在nodelay参数，多余的请求立刻丢弃，返回503，该参数可以不存在。</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://smileyi.gitee.io/2019/07/13/Nginx限流配置/" data-id="ck5390nr4000ekeczjydaazhr" class="article-share-link">分享</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/原创/">原创</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-Mysql分区" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2019/06/23/Mysql分区/" class="article-date">
  <time datetime="2019-06-23T13:45:16.000Z" itemprop="datePublished">2019-06-23</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/Mysql/">Mysql</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2019/06/23/Mysql分区/">Mysql分区</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><p>面对单表存有大量数据，mysql的查询及插入效率会变低，除了传统的分库分表方法外，mysql内置一种分区的方法（partition），可以按照一定规则将同一张表的数据存入不同的用户表空间文件中（ibd文件），提高mysql的查询效率，与分表相比，查询全部数据的时候不需要再使用union all联合查询，但索引页文件并未拆分，所以在高并发的情况下，分区方式的锁占用要高于分表方式。</p>
<h3 id="用法"><a href="#用法" class="headerlink" title="用法"></a>用法</h3><h4 id="1-range分区"><a href="#1-range分区" class="headerlink" title="1.range分区"></a>1.range分区</h4><p>按照主键范围将数据存储至不同的ibd文件当中，当删除分区时，该分区中所存储的条目也一并删除。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">create table t_user(</span><br><span class="line">    id int unsigned not null auto_increment,</span><br><span class="line">    name varchar(50),</span><br><span class="line">    age tinyint(3),</span><br><span class="line">    primary key(`id`)</span><br><span class="line">) partition by range(`id`) (</span><br><span class="line">    partition p1 values less than (1000),</span><br><span class="line">    partition p2 values less than (2000),</span><br><span class="line">    partition p3 values less than maxvalue</span><br><span class="line">);</span><br></pre></td></tr></table></figure></p>
<h4 id="2-list分区"><a href="#2-list分区" class="headerlink" title="2.list分区"></a>2.list分区</h4><p>当主键命中分区的指定列表时，将条目存入对应的分区当中，该方案没有类似range方式的兜底策略（less than maxvalue），所有值必须预设到列表当中<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">create table t_user(</span><br><span class="line">    id int unsigned not null auto_increment,</span><br><span class="line">    name varchar(50),</span><br><span class="line">    age tinyint(3),</span><br><span class="line">    primary key(`id`)</span><br><span class="line">) partition by list(`id`) (</span><br><span class="line">    partition p1 values in (1, 3, 5, 7, 9),</span><br><span class="line">    partition p2 values in (2, 4, 6, 8, 10)</span><br><span class="line">);</span><br></pre></td></tr></table></figure></p>
<h4 id="3-hash分区"><a href="#3-hash分区" class="headerlink" title="3.hash分区"></a>3.hash分区</h4><p>对主键进行hash映射，数据存入对应的分区当中<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">create table t_user(</span><br><span class="line">    id int unsigned not null auto_increment,</span><br><span class="line">    name varchar(50),</span><br><span class="line">    age tinyint(3),</span><br><span class="line">    primary key(`id`)</span><br><span class="line">) partition by hash(`id`) partitions 4;</span><br></pre></td></tr></table></figure></p>
<h3 id="管理"><a href="#管理" class="headerlink" title="管理"></a>管理</h3><h4 id="删除分区"><a href="#删除分区" class="headerlink" title="删除分区"></a>删除分区</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">alter table t_user drop partition p2;</span><br></pre></td></tr></table></figure>
<h4 id="新增分区"><a href="#新增分区" class="headerlink" title="新增分区"></a>新增分区</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"># 新增range分区</span><br><span class="line">alter table t_user add partition (partition p3 values less than maxvalue);</span><br><span class="line"></span><br><span class="line"># 新增list分区</span><br><span class="line">alter table t_user add partition (partition p3 values in (12, 14, 16, 18));</span><br><span class="line"></span><br><span class="line"># 新增hash分区</span><br><span class="line">alter table t_user add partition partitions 5;</span><br></pre></td></tr></table></figure>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://smileyi.gitee.io/2019/06/23/Mysql分区/" data-id="ck5390nr3000ckeczq29cysor" class="article-share-link">分享</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/原创/">原创</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-Rsa算法" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2019/04/15/Rsa算法/" class="article-date">
  <time datetime="2019-04-15T03:22:19.000Z" itemprop="datePublished">2019-04-15</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/算法/">算法</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2019/04/15/Rsa算法/">Rsa算法</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h4 id="一、介绍"><a href="#一、介绍" class="headerlink" title="一、介绍"></a>一、介绍</h4><p>1977年，三位数学家Rivest、Shamir 和 Adleman 设计了一种算法，可以实现非对称加密。这种算法用他们三个人的名字命名，叫做RSA算法。从那时直到现在，RSA算法一直是最广为使用的”非对称加密算法”。毫不夸张地说，只要有计算机网络的地方，就有RSA算法。</p>
<p>对极大整数做因数分解的难度决定了RSA算法的可靠性。换言之，对一极大整数做因数分解愈困难，RSA算法愈可靠。假如有人找到一种快速因数分解的算法的话，那么用RSA加密的信息的可靠性就肯定会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA钥匙才可能被强力方式解破。到目前为止，世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长，用RSA加密的信息实际上是不能被解破的。</p>
<h4 id="二、步骤"><a href="#二、步骤" class="headerlink" title="二、步骤"></a>二、步骤</h4><ol>
<li>选取两个互质的整数p和q，互质即p与q的最大公约数为1, 为了方便计算fn，一般直接选取两个质数。</li>
<li>计算p和q的乘积n，n的二进制位数就是密钥长度，一般是1024位，重要场合位2048位</li>
<li>计算n的欧拉函数fn，欧拉函数：即在[1,n)的区间中，与n互质的整数个数。若p、q都为质数，则fn=(p-1)*(q-1)</li>
<li>选取整数e，使得 1 &lt; e &lt; fn 且 e 与 fn 互质</li>
<li>计算e对于fn的模版元素d，即 e * d % fn == 1，根据欧拉定理，整数d一定存在</li>
<li>计算完成，公钥为n和e，私钥为n和d</li>
</ol>
<h4 id="三、加密和解密"><a href="#三、加密和解密" class="headerlink" title="三、加密和解密"></a>三、加密和解密</h4><p>根据上面的步骤，我们获取了公钥n和e和私钥n和d，假设要加密的明文为m，则密文c等于m的e次方除以n的余数：<br><strong>加密：c = m ** e % n</strong><br>要获得的明文m等于c的d次方除以n的余数：<br><strong>解密：m = c ** d % n</strong><br>加密过程用到了n、e，解密的过程用到n、d，至此实现了非对称加密的算法。</p>
<h4 id="四、举例"><a href="#四、举例" class="headerlink" title="四、举例"></a>四、举例</h4><ol>
<li>p = 47; q = 23</li>
<li>n = 47 * 23 = 1081</li>
<li>fn = (47 - 1) * (23 - 1) = 1012</li>
<li>e = 41 // 1 &lt; e &lt; fn &amp;&amp; e 与 fn 互质</li>
<li>d = 469 //模反元素(41 * 469) % 1012 = 1</li>
<li>加密：设明文 m = 16，则密文 c = 16 ** 41 % 1081 = 196</li>
<li>解密：密文 c = 196，则明文 m = 196 ** 469 % 1081 = 16</li>
</ol>
<h4 id="五、安全性"><a href="#五、安全性" class="headerlink" title="五、安全性"></a>五、安全性</h4><p>在密钥的生成步骤中一共出现了6个数字(p q n fn e d)，其中公钥n、e公开，其余四个不需要公开，若要破解，需要根据n和e推导出私钥d：</p>
<ol>
<li>已知ed % fn = 1, 只有知道e和fn才能推导出d</li>
<li>已知fn = (p-1) * (q-1), 只有知道p和q才能推导出fn</li>
<li>n = p * q, 只有将n因数分解才能算出p和q</li>
</ol>
<p>所以如果n被因数分解，d就可以算出，可是，大整数的因数分解，是一件非常困难的事情。目前，除了暴力破解，还没有发现别的有效方法。rsa的算法可靠性正是建立在此基础之上。</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://smileyi.gitee.io/2019/04/15/Rsa算法/" data-id="ck5390nrf0010kecz7xa1y0e2" class="article-share-link">分享</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/原创/">原创</a></li></ul>

    </footer>
  </div>
  
</article>


  


  <nav id="page-nav">
    
    <span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><a class="page-number" href="/page/3/">3</a><a class="extend next" rel="next" href="/page/2/">下一页 &raquo;</a>
  </nav>

</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">分类</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Docker/">Docker</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Linux/">Linux</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/MacOS/">MacOS</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Mysql/">Mysql</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Nginx/">Nginx</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/PHP/">PHP</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Swoole/">Swoole</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/算法/">算法</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/网络/">网络</a><span class="category-list-count">1</span></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">标签</h3>
    <div class="widget">
      <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/原创/">原创</a><span class="tag-list-count">10</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/总结/">总结</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/笔记/">笔记</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/转载/">转载</a><span class="tag-list-count">2</span></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">归档</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/01/">一月 2020</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/07/">七月 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/06/">六月 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/04/">四月 2019</a><span class="archive-list-count">7</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/03/">三月 2019</a><span class="archive-list-count">4</span></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">最新文章</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2020/01/05/Swoole之server/">swoole之server</a>
          </li>
        
          <li>
            <a href="/2020/01/02/Certbot-免费的ssl证书/">Certbot--免费的ssl证书</a>
          </li>
        
          <li>
            <a href="/2019/07/13/Nginx限流配置/">Nginx限流配置</a>
          </li>
        
          <li>
            <a href="/2019/06/23/Mysql分区/">Mysql分区</a>
          </li>
        
          <li>
            <a href="/2019/04/15/Rsa算法/">Rsa算法</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2020 王中艺<br>
      <a href="http://www.beian.miit.gov.cn/">京ICP备18032247号-2</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">首页</a>
  
    <a href="/archives" class="mobile-nav-link">归档</a>
  
</nav>
    

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>


  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css">
  <script src="/fancybox/jquery.fancybox.pack.js"></script>


<script src="/js/script.js"></script>



  </div>
</body>
</html>